#include "bsp_main.h"

using namespace std;

BSP::BSP(){
    pheader = new bspHeader_t; 
	ptexture = new bspTexture_t; 
	pplane = new bspPlane_t; 
	pbrushside = new bspBrushSide_t; 
	pbrush = new bspBrush_t; 
	pvertex = new bspVertex_t; 
	pface = new bspFace_t; 
	input >> hex;
    };
BSP::~BSP(){};

void BSP::LoadBSP(string filename){
	/* First 12 bytes = header (type, version, num of lumps)*/
	unsigned int numLumps, offset;
	bspLump_t *lump = new bspLump_t;

	input.open("test.bsp", ios::binary);

    input.read((char*)pheader->type, 4);
	input.read((char*)&(pheader->version), 4);
	
	for(int i = 0; i < LUMPNUM; i++){
		input.read((char*)&(lump->length), 4);
		input.read((char*)&(lump->offset), 4);

		cout << "Length: " << lump->length << " Offset: " << lump->offset << endl;

		pheader->lumphead.push_back(*lump);
	}

	//*lump = header->lumphead.at(LUMP_SHADERS);
	
    // PAY ATTENTION TO THIS FOR ACCESSING MEMBERS LATER
	//cout << "TEST OFFSET " << lump->offset << endl;
	

	/*input.read((char*)&numLumps, 4);
	input.read((char*)&offset, 4);*/


	cout << pheader->type << " version " << pheader->version << endl;
	cout << "Loading " << filename << endl;

	this->LoadShaderLump();
	this->LoadPlanesLump();
	this->LoadBrushSidesLump();
	this->LoadBrushesLump();

	this->LoadDVertsLump();
}


/* The Ripper */
int BSP::ExportLightmapsMain(int argc, char** argv){
	if(argc < 1){
		cout << "Usage: cod4map2 -export <mapname>" << endl;
		return 0;
	}else{
		cout << "Woohoo!" << endl;
	}

	return 0;
}


/* The Mender */
int BSP::ImportLightmapsMain(int argc, char** argv){
	int i, x, y, len, width, height; 
	string dirname; 
	
	vector<unsigned char> lightmap; 
	vector<unsigned char> buffer;
	vector<unsigned char> pixels; 
	vector<unsigned char> in; 
	vector<unsigned char> out; 

	if(argc < 1){
		cout << "Usage: cod4map2 -import <mapname>" << endl;
		return 0;
	}
	//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	//DONT FORGET TO ADD SUPPORT FOR DIRECTORY HOPPING
	//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	string filename = argv[argc];

    cout << "Loading " << filename << endl;
	this->LoadBSP(filename);

	return 0;

}

void BSP::LoadShaderLump(){
	int numTex = (pheader->lumphead.at(LUMP_SHADERS).length / sizeof(bspTexture_t));
	cout << numTex << endl;

	input.seekg(pheader->lumphead.at(LUMP_SHADERS).offset);
	for(int i = 0; i < numTex; i++){
		input.read((char*)ptexture->name, 64);
		input.read((char*)&(ptexture->flags), 4);
		input.read((char*)&(ptexture->contents), 4); 

		cout << "Before Push_Back: " << ptexture->name << endl;
		textures.push_back(*ptexture);
	}


}
void BSP::LoadLightmapsLump(){
}
void BSP::LoadPlanesLump(){
	int numPlanes = (pheader->lumphead.at(LUMP_PLANES).length / sizeof(bspPlane_t));

	input.seekg(0);
	input.seekg(pheader->lumphead.at(LUMP_PLANES).offset);
	for(int i = 0; i < numPlanes; i++){
		input.read((char*)&(pplane->normal), 12); 
		input.read((char*)&(pplane->dist), 4);

			cout << "Plane Normal XYZ " << pplane->normal[0] << " " << pplane->normal[1] << " " << pplane->normal[2] << endl;
			cout << "Plane Distance From Origin: " << pplane->dist << endl;


		planes.push_back(*pplane);
	}
	
}
void BSP::LoadBrushSidesLump(){
	int numSides = (pheader->lumphead.at(LUMP_BRUSHSIDES).length / sizeof(bspBrushSide_t));

	input.seekg(0);
	input.seekg(pheader->lumphead.at(LUMP_BRUSHSIDES).offset);
	cout << "Pointer Pos: " << input.tellg() << " Offset: " << pheader->lumphead.at(LUMP_BRUSHSIDES).offset << endl;

	for(int i = 0; i < numSides; i++){
		input.read((char*)pbrushside->planeNum, 4);
		input.read((char*)&(pbrushside->textureNum), 4); //not used for decompiling purposes. 

		cout << "Plane Index: " << pbrushside->planeNum << " Texture Index: " << pbrushside->textureNum << endl;
		

		brushsides.push_back(*pbrushside);
	}
}
void BSP::LoadBrushesLump(){
	int num = (pheader->lumphead.at(LUMP_BRUSHES).length / sizeof(bspBrush_t));

	cout << "size = " << (pheader->lumphead.at(LUMP_BRUSHES).length / sizeof(bspBrush_t))<< endl;

	input.seekg(pheader->lumphead.at(LUMP_BRUSHES).offset);

	for(int i = 0; i < num; i++){
		input.read((char*)&(pbrush->firstSide), 4); 
		//input.read((char*)&(pbrush->numSides), 4);
		//input.read((char*)&(pbrush->textureNum), 4);

		cout << "First Side: " << pbrush->firstSide << endl;
		//cout << "Number of Sides: " << pbrush->numSides << endl;
		//cout << "Texture Number: " << pbrush->textureNum << endl;

		brush.push_back(*pbrush);
	}
	
}
void BSP::LoadFogsLump(){
}
void BSP::LoadTSoupLump(){
}
void BSP::LoadDVertsLump(){
	int num = (pheader->lumphead.at(LUMP_DVERTS).length / sizeof(bspVertex_t));

	input.seekg(pheader->lumphead.at(LUMP_DVERTS).offset);

	for(int i = 0; i < num; i++){
		input.read((char*)&(pvertex->xyz), 12);
		input.read((char*)&(pvertex->st), 8);
		input.read((char*)&(pvertex->lightmap), 8);
		input.read((char*)&(pvertex->normal), 12);
		input.read((char*)pvertex->color, 4);

		vertices.push_back(*pvertex);
		//cout << "ST: " << pvertex->st[0] << " " << pvertex->st[1] << endl;//<< " ST: " << pvertex->st[0] << " LIGHTMAP: " << pvertex->lightmap[0] << " NORMAL: " << pvertex->normal[0] << endl;
		//cout << "LIGHTMAP: " << pvertex->lightmap[0] << " " << pvertex->lightmap[1] << endl;
	}

}
void BSP::LoadDIndexesLump(){
}
void BSP::LoadCullgroupsLump(){
}
void BSP::LoadCullgroupIndexesLump(){
}
void BSP::LoadPortalVertsLump(){
}
void BSP::LoadOccludersLump(){
}
void BSP::LoadOccluderPlanesLump(){
}
void BSP::LoadOccluderEdgesLump(){
}
void BSP::LoadOccluderIndexesLump(){
}
void BSP::LoadAABBLump(){
}
void BSP::LoadCellsLump(){
}
void BSP::LoadPortalsLump(){
}
void BSP::LoadLightIndexLump(){
}
void BSP::LoadNodesLump(){
}
void BSP::LoadLeafsLump(){
}
void BSP::LoadLeafBrushesLump(){
}
void BSP::LoadLeafSurfacesLump(){
}
void BSP::LoadPatchCollisionLump(){
}
void BSP::LoadCollisionVertsLump(){
}
void BSP::LoadCollisionIndexesLump(){
}
void BSP::LoadModelsLump(){
}
void BSP::LoadVisibilityLump(){
}
void BSP::LoadEntitiesLump(){
}
void BSP::LoadLightsLump(){
}
void BSP::LoadUnknown1Lump(){
}
void BSP::LoadUnknown2Lump(){
}

int BSP::ConvertBSPMain(int argc, char** argv){
	string argv_string;

	if(argc < 1){
		cout << "Usage: cod4map2 -convert [game] <mapname>" << endl;
		return 0;
	}

	for(int i = 1; i < argc; i++){
		argv_string = argv[i];

		if(!argv_string.compare("-cod1")){
			cout << "Game: Call of Duty 1" << endl;
		}
		else if(!argv_string.compare("-cod4")){
			cout << "Game: Call of Duty 4" << endl;
		}
		else if(!argv_string.compare("-cod5")){
			cout << "Game: Call of Duty 5" << endl;
		}
		else{
			cout << "Game not specified. Defaulting to Call of Duty 1" << endl;
			cout << "Game Options are: -cod1, -cod4, and -cod5" << endl;
		}
	}
    string filename = argv[argc];
	string extension(".bsp");

	/* SANITY CHECK */
	if(filename.rfind(extension) == string::npos){
		cout << "Specified file is not a .bsp file." << endl;
		return 0;
	}else{

	this->LoadBSP(filename);
	}

	return 0;
}

